﻿using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Inovout.Data.Domain;
using Inovout.Descriptor;

namespace System.Web.Mvc.Html
{
    public class Tree<TModel, TContent> : Tree<TModel>
    {
        public Tree(TModel source, string keyProperty, string contentProperty, Func<TContent, object> cntentRenderFunc, params string[] selectedKeys)
            : base(source, keyProperty, contentProperty, c => cntentRenderFunc((TContent)c), selectedKeys)
        {
        }
    }
    public class Tree<TModel> : Tree
    {
        public Tree(TModel source, string keyProperty, string contentProperty, Func<object, object> cntentRenderFunc, params string[] selectedKeys)
            : base(typeof(TModel), source, keyProperty, contentProperty, selectedKeys, cntentRenderFunc)
        {
            Expression<Func<ITreeDataObject, object>> childrenPropertyAccessor = m => m.Children;
            base.ChildrenProperty = ExpressionHelper.GetExpressionText(childrenPropertyAccessor);
        }
    }
    public class Tree : TreeNode
    {
        public Tree(Type modelType, object source, string keyProperty, string contentProperty, string[] selectecdKeys, Func<object, object> cntentRenderFunc = null, string childrenProperty = "Children")
            : base(null, TypeDescriptor.Get(modelType), source, keyProperty, contentProperty, childrenProperty, cntentRenderFunc)
        {
            this.InternalSelectedKeys = selectecdKeys ?? new string[0];
            this.Root = this;
            this.Selected = this.Root.InternalSelectedKeys.Contains(this.Key);
        }

        public string[] AllSelectedKeys { get { return this.InternalSelectedKeys ?? new String[0]; } }
        internal string[] InternalSelectedKeys { get; set; }
        public object Source { get { return base.Model; } }
        public bool ExpandAll { get; set; }
        public bool Multiple { get; set; }
        public bool Checkable { get; set; }
        public override string[] SelectedKeys
        {
            get
            {
                return this.Selected ? base.SelectedKeys.Union(new string[] { this.Key }).ToArray() : base.SelectedKeys;
            }
        }
    }

    public class TreeNode
    {
        public TreeNode(Tree root, TypeDescriptor modelTypeDescriptor, object model, string keyProperty, string contentProperty,
            string childrenProperty, Func<object, object> cntentRenderFunc = null)
        {
            this.Root = root;
            this.ModelTypeDescriptor = modelTypeDescriptor;
            this.Model = model;
            this.KeyProperty = keyProperty;
            this.ContentProperty = contentProperty;
            this.ChildrenProperty = childrenProperty;
            this.CntentRenderFunc = cntentRenderFunc ?? (this.Root == null ? null : this.Root.CntentRenderFunc);

            this.Key = modelTypeDescriptor.GetProperty(keyProperty).GetValue(model).ToString();
            object content = string.IsNullOrEmpty(ContentProperty) ? model : modelTypeDescriptor.GetProperty(contentProperty).GetValue(model);
            this.Content = this.RenderContent(content);
            if (this.Root != null)
            {
                this.Selected = this.Root.InternalSelectedKeys.Contains(this.Key);
            }

        }
        internal virtual object RenderContent(object content)
        {
            return this.CntentRenderFunc == null ? content : CntentRenderFunc(content);
        }
        public Func<object, object> CntentRenderFunc { get; set; }
        internal Tree Root { get; set; }
        public TypeDescriptor ModelTypeDescriptor { get; private set; }
        public object Model { get; private set; }
        public string KeyProperty { get; private set; }
        public string ContentProperty { get; private set; }

        public string Key { get; set; }
        public object Content { get; set; }
        public bool Disabled { get; set; }
        public bool Checked { get; set; }
        public bool Selected { get; set; }
        public bool Expanded { get; set; }
        public bool IsLeaf { get; set; }

        private IEnumerable<TreeNode> children;
        public string ChildrenProperty { get; protected set; }
        public IEnumerable<TreeNode> Children
        {
            get
            {
                if (children == null)
                {
                    IEnumerable source = ModelTypeDescriptor.GetProperty(ChildrenProperty).GetValue(Model) as IEnumerable;
                    List<TreeNode> result = new List<TreeNode>();
                    foreach (var model in source)
                    {
                        result.Add(new TreeNode(this.Root, ModelTypeDescriptor, model, KeyProperty,
                            ContentProperty, ChildrenProperty));
                    }
                    children = result;
                }
                return children;
            }
        }
        public virtual string[] ExpandedKeys { get { return this.Children.Where(n => n.Expanded).Select(n => n.Key).ToArray(); } }
        public virtual string[] CheckedKeys { get { return this.Children.Where(n => n.Checked).Select(n => n.Key).ToArray(); } }
        public virtual string[] SelectedKeys { get { return this.Children.Where(n => n.Selected).Select(n => n.Key).ToArray(); } }
    }

}

